#include "SceneLoader.h"
#include "Graph.h"
#include "StaticObject.h"

SceneLoader::SceneLoader(void) : mpScene(0)
{
}

SceneLoader::~SceneLoader(void)
{
}

SceneLoader SceneLoader::getInstance(void)
{
	static SceneLoader self;
	return self;
}

Scene* SceneLoader::loadScene(const std::string& sceneFile, Ogre::SceneManager* pSceneMgr)
{
	TiXmlDocument* pDoc = new TiXmlDocument(sceneFile.c_str());
	if(pDoc->LoadFile())
	{
		mpScene = new Scene();
		mpScene->setSceneManager(pSceneMgr);

		TiXmlElement* pElem = pDoc->FirstChildElement();
		for(pElem = pElem->FirstChildElement(); pElem != 0; pElem = pElem->NextSiblingElement())
		{
			std::string tagName = pElem->Value();
			if(tagName.compare("plane")==0)
			{
				processPlane(pElem, pSceneMgr);
			}
			else if(tagName.compare("light")==0)
			{
				processLight(pElem, pSceneMgr);
			}
			else if(tagName.compare("nodelist")==0)
			{
				processNodes(pElem, pSceneMgr);
			}
			else if(tagName.compare("structurelist") == 0)
			{
				processStructures(pElem, pSceneMgr);
			}
			else if(tagName.compare("agentlist") == 0)
			{
				processAgents(pElem, pSceneMgr);
			}
		}
	}

	delete pDoc;

	pSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");
	pSceneMgr->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_MODULATIVE);

	//No longer care about the generated scene
	Scene* pScene = mpScene;
	mpScene = NULL;

	return pScene;
}

void SceneLoader::processPlane(TiXmlElement* pElem, Ogre::SceneManager* pSceneMgr)
{
	Ogre::Plane plane(Ogre::Vector3::UNIT_Y, 0);
	std::string matName = "Examples/Rockwall"; //Default material
	int width = 1000; //default size
	int height = 1000;

	for(TiXmlAttribute* pAttrib = pElem->FirstAttribute(); pAttrib != 0; pAttrib = pAttrib->Next())
	{
		std::string attrName = pAttrib->Name();
		if(attrName.compare("material")==0)
			matName = pAttrib->Value();
		else if(attrName.compare("width")==0)
			width = atoi(pAttrib->Value());
		else if(attrName.compare("height")==0)
			height = atoi(pAttrib->Value());
	}

	Ogre::MeshManager::getSingleton().createPlane("ground", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
		plane, width, height, 20, 20, true, 1, 5, 5, Ogre::Vector3::UNIT_Z);

	Ogre::Entity* pGround = pSceneMgr->createEntity("GroundEntity", "ground");
	pSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pGround);
 
	pGround->setMaterialName(matName);
	pGround->setCastShadows(false);

	mpScene->setGroundEntity(pGround);
}

void SceneLoader::processLight(TiXmlElement* pElem, Ogre::SceneManager* pSceneMgr)
{
	Ogre::ColourValue colour(0.5f,0.5f,0.5f);
	Ogre::Vector3 position(Ogre::Vector3::ZERO);
	int type = -1;
	for(TiXmlAttribute* pAttrib = pElem->FirstAttribute(); pAttrib != 0; pAttrib = pAttrib->Next())
	{
		std::string attrName = pAttrib->Name();
		if(attrName.compare("type") == 0)
		{
			std::string typeName = pAttrib->Value();
			if(typeName.compare("ambient") == 0)
				type = 0;
			else if(typeName.compare("point") == 0)
				type = 1;
		}
		else if(attrName.compare("r") == 0)
		{
			colour.r = atof(pAttrib->Value());
		}
		else if(attrName.compare("g") == 0)
		{
			colour.g = atof(pAttrib->Value());
		}
		else if(attrName.compare("b") == 0)
		{
			colour.b = atof(pAttrib->Value());
		}
		else if(attrName.compare("x") == 0)
		{
			position.x = atof(pAttrib->Value());
		}
		else if(attrName.compare("y") == 0)
		{
			position.y = atof(pAttrib->Value());
		}
		else if(attrName.compare("z") == 0)
		{
			position.z= atof(pAttrib->Value());
		}
	}
				
	if(type == 0)
	{
		mpScene->setAmbientLight(colour);
	}
	else if(type == 1)
	{
		mpScene->setPointLight(position, colour, colour);
	}
}

void SceneLoader::processNodes(TiXmlElement* pElem, Ogre::SceneManager* pSceneMgr)
{
	Graph* pGraph = Graph::getInstance();
	for(TiXmlElement* pNode = pElem->FirstChildElement(); pNode != 0; pNode = pNode->NextSiblingElement())
	{
		int x = 0;
		int z = 0;
		int c = 0;
		for(TiXmlAttribute* pAttrib = pNode->FirstAttribute(); pAttrib != 0; pAttrib = pAttrib->Next())
		{
			std::string attrName = pAttrib->Name();
			if(attrName.compare("x") == 0)
				x = atoi(pAttrib->Value());
			else if(attrName.compare("z") == 0)
				z = atoi(pAttrib->Value());
		}

		char name[24];
		sprintf(name,"%ix%i",x,z);
		PathNode* pGraphNode = pGraph->addNode(name, Ogre::Vector3(x,0,z), pSceneMgr);
		
		for(TiXmlElement* pEdge = pNode->FirstChildElement(); pEdge != 0; pEdge = pEdge->NextSiblingElement())
		{
			std::string target = "";
			int cost = 0;
			int exposure = 0;
			for(TiXmlAttribute* pAttrib = pEdge->FirstAttribute(); pAttrib != 0; pAttrib = pAttrib->Next())
			{
				std::string attrName = pAttrib->Name();
				if(attrName.compare("target") == 0)
					target = pAttrib->Value();
			}
			pGraph->connect(pGraphNode,target,pSceneMgr);
		}
	}
}

void SceneLoader::processStructures(TiXmlElement* pElem, Ogre::SceneManager* pSceneMgr)
{
	for(TiXmlElement* pStructure = pElem->FirstChildElement(); pStructure != 0; pStructure = pStructure->NextSiblingElement())
	{
		std::string mesh = "barrel.mesh"; //Default mesh
		Ogre::Vector3 pos(Ogre::Vector3::ZERO);
		float scale = 0.0f;
		Ogre::Radian rot(0.0f);
		
		for(TiXmlAttribute*pAttrib = pStructure->FirstAttribute(); pAttrib != 0; pAttrib = pAttrib->Next())
		{
			std::string attrName = pAttrib->Name();
			if(attrName.compare("mesh") == 0)
				mesh = pAttrib->Value();
			else if(attrName.compare("x") == 0)
				pos.x = atoi(pAttrib->Value());
			else if(attrName.compare("y") == 0)
				pos.y = atoi(pAttrib->Value());
			else if(attrName.compare("z") == 0)
				pos.z = atoi(pAttrib->Value());
			else if(attrName.compare("scale") == 0)
				scale = atof(pAttrib->Value());
			else if(attrName.compare("r") == 0)
				rot = atof(pAttrib->Value());
		}

		StaticObject* pObject = new StaticObject(mesh, pos, pSceneMgr);
		pObject->setScale(Ogre::Vector3(scale));
		pObject->setRotation(Ogre::Radian(rot));
		mpScene->addStaticObject(pObject);
		pObject = NULL;
	}
}

void SceneLoader::processAgents(TiXmlElement* pElem, Ogre::SceneManager* pSceneMgr)
{
	Graph* pGraph = Graph::getInstance();

	for(TiXmlElement* pAgent = pElem->FirstChildElement(); pAgent != 0; pAgent = pAgent->NextSiblingElement())
	{
		TiXmlAttribute* pAttrib = pAgent->FirstAttribute();
		std::string type = pAttrib->Value();
		
		if(type.compare("ninja") == 0)
		{
			Agent* pAgentObject = new Agent(pSceneMgr);

			for(pAttrib = pAttrib->Next(); pAttrib != 0; pAttrib = pAttrib->Next())
			{
				std::string attrName = pAttrib->Name();
				if(attrName.compare("node") == 0)
				{
					pAgentObject->setNode(pGraph->findNode(pAttrib->Value()));
				}
			}

			for(TiXmlElement* pAction = pAgent->FirstChildElement(); pAction != 0; pAction = pAction->NextSiblingElement())
			{
				int type = 0;
				float time = 0;
				PathNode* pTarget = NULL;
				bool repeat = false;
				
				for(pAttrib = pAction->FirstAttribute(); pAttrib != 0; pAttrib = pAttrib->Next())
				{
					std::string attrName = pAttrib->Name();
					if(attrName.compare("type") == 0)
						type = atoi(pAttrib->Value());
					else if(attrName.compare("time") == 0)
						time = atof(pAttrib->Value());
					else if(attrName.compare("target") == 0)
						pTarget = pGraph->findNode(pAttrib->Value());
					else if(attrName.compare("repeat") == 0)
						repeat = (!atoi(pAttrib->Value())==0);
				}

				pAgentObject->pushAction((Action::ACTION_TYPE)type, time, pTarget, repeat);
			}

			mpScene->addAgent(pAgentObject);
		}
	/*	else //robot
		{
			Robot* pRobot = new Robot(mSceneMgr);
			
			for(pAttrib = pAttrib->Next(); pAttrib != 0; pAttrib = pAttrib->Next())
			{
				std::string attrName = pAttrib->Name();
				
				if(attrName.compare("node") == 0)
				{
					pRobot->setNode(mpGraph->findNode(pAttrib->Value()));
				}
			}

			for(TiXmlElement* pAction = pAgent->FirstChildElement(); pAction != 0; pAction = pAction->NextSiblingElement())
			{
				int type = 0;
				float time = 0;
				PathNode* pTarget = NULL;
				bool repeat = false;
				
				for(pAttrib = pAction->FirstAttribute(); pAttrib != 0; pAttrib = pAttrib->Next())
				{
					std::string attrName = pAttrib->Name();
					if(attrName.compare("type") == 0)
						type = atoi(pAttrib->Value());
					else if(attrName.compare("time") == 0)
						time = atof(pAttrib->Value());
					else if(attrName.compare("target") == 0)
						pTarget = mpGraph->findNode(pAttrib->Value());
					else if(attrName.compare("repeat") == 0)
						repeat = (!atoi(pAttrib->Value())==0);
				}

				pRobot->pushAction((Action::ACTION_TYPE)type, time, pTarget, repeat);
			}

			mRobots.push_back(pRobot);
		}*/
	}
}